#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include "include/params.h"
#include "include/types.h"
#include "include/operat.h"
#include "include/module.h"
#include "include/virtware.h"
#include "include/vmerr.h"
#include "include/libcore.h"
#include "include/nr_excp.h"

status cpu_init (struct rv32cpu* cpu, struct environ * env);
status cpu_tick (struct rv32cpu * cpu);
status cpu_do_reset (struct rv32cpu* cpu); // 重置CPU
void * cpu_thread (void* arg);
status cpu_do_run (struct rv32cpu* cpu);
status cpu_wait_until_stop (struct rv32cpu* cpu);
status cpu_add_module (struct rv32cpu * cpu, struct module * mod);
status cpu_remove_module(struct rv32cpu * cpu, modid_t modid);
status cpu_execute_inst (struct rv32cpu * cpu);
status cpu_raise_excep_sync (struct rv32cpu * cpu, word cause);
status cpu_raise_excep_async (struct rv32cpu * cpu, word cause);
bool test_and_load_excep (struct rv32cpu * cpu); // 检测并加载异常
status cpu_handle_excep (struct rv32cpu * cpu); // 处理异常
status cpu_ctl_reset (struct rv32cpu * cpu);
status cpu_ctl_start (struct rv32cpu * cpu);
status cpu_ctl_stop (struct rv32cpu * cpu);
status cpu_ctrl (struct rv32cpu * cpu, enum cpu_ctl_arg arg);

status
cpu_do_reset (struct rv32cpu* cpu) {
    status stat = STAT_SUCCESS;
    cpu->pc = CPU_ORIPC;
    cpu->mode = CPU_MODE_M;
    bzero (&cpu->intrp, sizeof (cpu->intrp));
    bzero (&cpu->stat, sizeof (cpu->stat));
    bzero (&cpu->regs, sizeof (cpu->regs));
    cpu->mtie = false;
    cpu->mtime = 0;
    cpu->mtimcmp = 0;
    return stat;
}
status
cpu_init (struct rv32cpu* cpu, struct environ * env) {
    status stat = STAT_SUCCESS;
    bzero (cpu, sizeof (struct rv32cpu));
    cpu->env = env;
    if(mlk_init (cpu->ctrl_mlk))
    if(pthread_attr_init (&cpu->thread_info.attr))
        stat |= ERR_THREAD;
    if (stat == STAT_SUCCESS)
        cpu->magic = BISCUIT_MAGIC;
    cpu_do_reset (cpu);
    return stat;
}

void *
cpu_thread (void* arg) {
    struct rv32cpu * self;
    status stat = STAT_SUCCESS;
    self = (struct rv32cpu *) arg;
    self->stat.running = true;
    DBG_LOG (cpu_thread, "CPU thread running.");
    while (!self->stat.stopsig) {
        self->regs[x0] = 0; // zero 寄存器清零
        stat = cpu_tick (self);
        if (stat != STAT_SUCCESS) {
            DBG_LOG (cpu_thread, "Error detected: 0x%llX", stat);
        }
    }
    self->stat.running = false;
    DBG_LOG (cpu_thread, "CPU thread exiting...");
    pthread_exit (NULL);
}



status
cpu_do_run (struct rv32cpu* cpu) {
    status stat = STAT_SUCCESS;
    if (!MAGIC_OK (cpu)) {
        stat |= ERR_MAGIC;
        DBG_LOG (cpu_do_run, "Magic error. CPU not ready yet.");
        goto error;
    }
    if (pthread_create (&cpu->thread_info.id,
        &cpu->thread_info.attr, cpu_thread, cpu)) {
        stat |= ERR_THREAD;
        goto error;
    }
    return stat;
    error:
    return stat;

}

status
cpu_wait_until_stop (struct rv32cpu* cpu) {
    status stat = STAT_SUCCESS;
    void * retval = NULL;
    if (!cpu->stat.running) 
        DBG_LOG (cpu_wait_until_stop, "CPU already stopped.");
    while (cpu->stat.running);
    if (pthread_join (cpu->thread_info.id, &retval)) {
        stat |= ERR_THREAD;
        goto error;
    }
    return stat;
    error:
    return stat;
}

status
cpu_add_module (struct rv32cpu * cpu, struct module * mod) {
    status stat = STAT_SUCCESS;
    count_t i;
    for (i = 0; i < mod->items.item_n; i++) {
        if (mod->items.item_list[i].type == MI_CPU_CSRRW) 
            add_module_item (cpu, csrrw, mod->items.item_list[i]);
        if (mod->items.item_list[i].type == MI_CPU_DECODER) 
            add_module_item (cpu, decoder, mod->items.item_list[i]);
        if (mod->items.item_list[i].type == MI_CPU_EXHDLR) 
            add_module_item (cpu, exhdlr, mod->items.item_list[i]);
    }
    if (stat & ERR_NRITEM) {
        fprintf (stderr, "cpu_add_module: Unable to add module, MAX_MOD_ITEMS reached.\n");
        DBG_LOG (cpu_add_module,"removing mod[%llu]::csr", mod->modid);
        remove_module_item (cpu, csrrw,mod->modid);
        DBG_LOG (cpu_add_module,"mod[%llu]::csr removed", mod->modid);
        DBG_LOG (cpu_add_module,"removing mod[%llu]::decoder", mod->modid);
        remove_module_item (cpu, decoder,mod->modid);
        DBG_LOG (cpu_add_module,"mod[%llu]::decoder removed", mod->modid);
        DBG_LOG (cpu_add_module,"removing mod[%llu]::excep", mod->modid);
        remove_module_item (cpu, exhdlr,mod->modid);
        DBG_LOG (cpu_add_module,"mod[%llu]::excep removed", mod->modid);
    }
    return stat;
}


status
cpu_remove_module(struct rv32cpu * cpu, modid_t modid) {
    status stat = STAT_SUCCESS;
    bool mod_exist = false;
    count_t i;
    for (i = 0; i < MAX_MOD_ITEM; i++) {
        if (cpu->mods.csrrw_modid[i] == modid){
            mod_exist = true;
            break;
        }
        if (cpu->mods.decoder_modid[i] == modid){
            mod_exist = true;
            break;
        }
        if (cpu->mods.exhdlr_modid[i] == modid){
            mod_exist = true;
            break;
        }
    }
    if (mod_exist == false) {
        stat |= ERR_MNOINST;
        goto error;
    }
    remove_module_item (cpu, csrrw, modid);
    remove_module_item (cpu, exhdlr, modid);
    remove_module_item (cpu, decoder, modid);
    return stat;
    error:
    return stat;
}

status
cpu_execute_inst (struct rv32cpu * cpu) {
    status stat = STAT_SUCCESS;
    struct req_stat rstat = REQS_INIT;
    exec_module_func (cpu, decoder, {
        .env = cpu->env,
        .saved_pc = cpu->pc,
        .rstat = &rstat
    });
    if (stat == STAT_SUCCESS)
        goto success;
    if (!rstat.req_ack) {
    //DBG_LOG (cpu_execute_inst, "Undefined instruction.");
        cpu_raise_excep_sync (cpu, EXCP_UNDEF_INST);
    }
    // return stat;
    success:
    return stat;
}

status
cpu_raise_excep_sync (struct rv32cpu * cpu, word cause) {
    status stat;
    stat = STAT_SUCCESS;
    // CHECK_MAGIC (cpu);
    struct intrp_desc intdesc_buf = {
        .source = INTR_SRC_SYNC,
        .cause = cause,
    };
    int op_suc;
    plk_lock (cpu->intrp.intrp_ring.plk, PLK_CPU);
    op_suc = ring_pushhd ((cpu->intrp.intrp_ring), intdesc_buf);
    plk_unlock (cpu->intrp.intrp_ring.plk, PLK_CPU);
    // cpu->intrp.enable = true; // 在此开中断,可使同步异常及时处理 (默认不支持中断嵌套)
    cpu->intrp.hdsig = true; // 设置handle signal,将在下一时钟处理
    //printf ("push excep:%X, stat:%d\n", cause ,op_suc);
    if (!op_suc) 
        stat |= ERR_FULLRING;
    // todo : 错误处理
    return stat;
}

status
cpu_raise_excep_async (struct rv32cpu * cpu, word cause) {
    status stat = STAT_SUCCESS;
    // CHECK_MAGIC (cpu);
    struct intrp_desc intdesc_buf = {
        .cause = cause,
        .source = INTR_SRC_ASYNC
    };
    int op_suc;
    plk_lock (cpu->intrp.intrp_ring.plk, PLK_CPU);
    op_suc = ring_pushtl ((cpu->intrp.intrp_ring), intdesc_buf);
    plk_unlock (cpu->intrp.intrp_ring.plk, PLK_CPU);
    if (!op_suc) 
        stat |= ERR_FULLRING;
    // todo : 错误处理
    return stat;
}

// 中断处理分两步:第一步装载(pending = 1) 第二部执行(pending = 0)
bool
test_and_load_excep (struct rv32cpu * cpu) {
    int op_suc;
    struct intrp_desc intdesc_buf;
    if (cpu->intrp.hdsig) {
    if (cpu->intrp.enable) {
        if (cpu->intrp.pending) { // 存在未决中断
            return true;
        } else {
            plk_lock (cpu->intrp.intrp_ring.plk, PLK_CPU);
            op_suc = ring_pophd (cpu->intrp.intrp_ring, intdesc_buf);
            plk_unlock (cpu->intrp.intrp_ring.plk, PLK_CPU);
            if (op_suc) {
                cpu->intrp.cause = intdesc_buf.cause;
                cpu->intrp.source = intdesc_buf.source;
                cpu->intrp.pending = true;
                //printf ("test_and_load_excep. src:%d source:%d\n", cpu->intrp.source, cpu->intrp.cause);
                return true;
            }
        }
    }
    cpu->intrp.hdsig = false;
    }
    return  false;
}

status
cpu_handle_excep (struct rv32cpu * cpu) {
    status stat = STAT_SUCCESS;
    struct req_stat rstat = REQS_INIT;
    // printf ("CPU handling excep, %d\n", cpu->intrp.cause);
    exec_module_func (cpu, exhdlr, {
        .env = cpu->env,
        .source = cpu->intrp.source,
        .cause = cpu->intrp.cause,
        .rstat = &rstat
    });
    cpu->intrp.pending = false; // 未决中断已处理
    cpu->intrp.enable = false; // 默认在此关中断
    if (stat != STAT_SUCCESS) {
        DBG_LOG (cpu_handle_excep, "Error occurred while handling exception.");
        stat |= ERR_MODFN;
        goto error;
    }
    return stat;
    error:
    return stat;
}

status
cpu_tick (struct rv32cpu * cpu) {
    status stat = STAT_SUCCESS;
    static uint64 tick_cnt = 0; // 设置在cpu_thread中更好些?
    if (tick_cnt++ % INTRPOLL_TIME == 0)
        cpu->intrp.hdsig = true; 
    if(PARAM_DEBUG) getchar ();
    DBG_LOG (cpu_tick, "Tick.");
    if (test_and_load_excep (cpu)) {
        stat |= cpu_handle_excep (cpu);
    } else {
        stat |= cpu_execute_inst (cpu);
    }
    cpu->mtime++;
    if (cpu->mtime >= cpu->mtimcmp && cpu->mtie) { // 模拟计时功能
        DBG_LOG (cpu_tick, "Raising mtime intrp...");
        cpu_raise_excep_sync (cpu, EXCP_TIMER);
        cpu->mtie = false; // 关计时中断
    }
    if (stat != STAT_SUCCESS)
        goto error;
    return stat;
    error:
    return stat;
}

status
cpu_ctl_reset (struct rv32cpu * cpu) {
    status stat = STAT_SUCCESS;
    if (cpu->stat.running) {
        DBG_LOG (cpu_ctl_reset, "CPU is running, stop CPU.");
        cpu->stat.stopsig = true; // 设置stopsig
        // 等待线程停止
        if (cpu_wait_until_stop(cpu)) {
            DBG_LOG (cpu_ctrl, "Unable to stop CPU.");
            stat |= ERR_CONTROL;
            goto error;
        }
    }
    cpu_do_reset (cpu);
    return stat;
    error:
    return stat;
}

status
cpu_ctl_start (struct rv32cpu * cpu) {
    status stat = STAT_SUCCESS;
    if (cpu->stat.running) {
        DBG_LOG (cpu_ctl_start, "CPU is running. invalid operation.");
        stat |= ERR_STATUS;
        goto error;
    }
    cpu->stat.stopsig = false;
    stat |= cpu_do_run (cpu);
    if (stat != STAT_SUCCESS) {
        DBG_LOG (cpu_ctl_start, "Unable to run.");
        stat |= ERR_CONTROL;
        goto error;
    }
    DBG_LOG (cpu_ctl_start, "Waiting for CPU thread.");
    while (!cpu->stat.running);
    return stat;
    error:
    return stat;
}

status
cpu_ctl_stop (struct rv32cpu * cpu) {
    status stat = STAT_SUCCESS;
    if (cpu->stat.stopsig == true) {
        DBG_LOG (cpu_ctl_stop, "CPU already stopped.");
        stat |= ERR_STATUS;
        goto error;
    }
    cpu->stat.stopsig = true; // 设置stopsig
    // 等待线程停止
    if (pthread_self () == cpu->thread_info.id) {
        DBG_LOG (cpu_ctl_stop, "CPU self");
        goto success;
    }
    if (cpu_wait_until_stop(cpu)) {
        DBG_LOG (cpu_ctl_stop, "Unable to stop CPU.");
        stat |= ERR_CONTROL;
        goto error;
    }
    success:
    return stat;
    error:
    return stat;
}

status
cpu_ctrl (struct rv32cpu * cpu, enum cpu_ctl_arg arg) {
    status stat = STAT_SUCCESS;
    mlk_lock (cpu->ctrl_mlk);
    switch (arg) {
    case CPU_CTL_RESET: {
        stat |= cpu_ctl_reset (cpu);
        break;
    } 
    case CPU_CTL_START: {
        stat |= cpu_ctl_start (cpu);
        break;
    } 
    case CPU_CTL_STOP: {
        stat |= cpu_ctl_stop (cpu);
        break;
    } 
    }
    mlk_unlock (cpu->ctrl_mlk);
    return stat;
}

